/******************************************************
* Team WB
* Brett Cate, William Kim
* 
* CPU ADT Header
*******************************************************/

#ifndef SC2_H
#include "sc2.h"
#endif
#ifndef REGISTERFILE_H
#include "registerFile.h"
#endif
#ifndef REGISTER16_H
#include "register16.h"
#endif
#ifndef ALU_H
#include "alu.h"
#endif
#ifndef MEMORYMODULE_H
#include "memoryModule.h"
#endif
#ifndef DEBUGMONITOR_H
#include "debugMonitor.h"
#endif

#ifndef CPU_H
#define CPU_H

struct DebugMonitor;

typedef struct cpu_str {
	RegisterFilePtr registerFile;
	RegisterPtr SW, PC, IR, MDR, MAR;
	ALUPtr alu;
	MemoryModulePtr mainMemory, IOPORTS;
	int macroState;
	int microState;
	int cursorX;
	int cursorY;
} CPU;

typedef CPU* CPUPtr;

// Operations

/*
Instantiates and returns a pointer to a new CPU object.

parameter (the_error): pointer to the error code value for this function.

return value: A pointer to this CPU object.
*/
CPUPtr cpu_new(int* the_error);

/*
Simulates a state machine using the CPU pointed to by the given CPUPtr,
and returns the value of the error code for the function.

parameter (the_cpu): Pointer the CPU to be used for this function.
parameter (the_debug_monitor_ptr): Pointer to the debug monitor whose
debug state is used by this function.

return value: The value of error code for this function.
*/
int cpu_run(CPUPtr the_cpu, struct DebugMonitor* the_debug_monitor_ptr);

/*
Fetches the instruction from memory and places it in the IR, increments the PC, and returns
the error code for this function.

parameter (the_cpu): Pointer to the CPU whose IR the instruction is placed in.

return value: the int error code value for this function.
*/
int cpu_fetchInstruction(CPUPtr the_cpu);

/*
Increments the PC in the given CPU.

parameter (the_cpu): Pointer to the cpu whose PC is incremented.

return value: the int value of the error code of this function.
*/
int cpu_incrementPC(CPUPtr the_cpu);

/*
Returns the opcode of the current instruction as a ushort and places the mod value 
for the instruction at the address of the given ushort parameter.

parameter (the_cpu): Pointer to the CPU whose IR the opcode is gathered from.
parameter (the_error): Pointer to the value of the error code for this function.
parameter (the_opcode_mod): Pointer to the ushort value where the opcode mod is placed.

return value: The ushort value of the opcode of the instruction in the given CPU.
*/
ushort cpu_decodeInstruction(CPUPtr the_cpu, int* the_error, ushort* the_opcode_mod);

/*
Puts the operands specified by the instruction in the given CPU's IR into the CPU's
ALU registers (A and B) and returns the value of the error code for this function.

parameter (the_cpu): Pointer to the CPU whose IR and ALU are used.

return value: The int value of the error code.
*/
int cpu_fetchOperands(CPUPtr the_cpu);

/*
Executes the instruction with the given opcode and mod, and returns the value
of the error code.

parameter (the_cpu): Pointer to the CPU used.
parameter (the_opcode): Opcode of the instruction.
parameter (the_mod): 3 bit mod value for the instruction.

return value: The int value of the error code.
*/
int cpu_executeInstruction(CPUPtr the_cpu, int the_opcode, int the_mod);








// Store Operations

/*
Selects the appropriate STW operation based on the given mod.

parameter (the_cpu): Pointer to the CPU to be used.
parameter (the_cpu): The mod value to be used.

return value: The int value of the error code.
*/
int cpu_STW(CPUPtr the_cpu, int the_mod);

/*
Selects the appropriate STB operation based on the given mod.

parameter (the_cpu): Pointer to the CPU to be used.
parameter (the_cpu): The mod value to be used.

return value: The int value of the error code.
*/
int cpu_STB(CPUPtr the_cpu, int the_mod);

/*
Stores the word in the register indicated by the instruction to the location in memory
indicated by the instruction, then returns the error code value. 
The instruction is in the IR of the given CPU. This store uses a register addressing mode.

parameter (the_cpu): Pointer to the CPU to be used.

return value: The int value of the error code.
*/
int cpu_STWRegister(CPUPtr the_cpu);

/*
Stores the low-order byte in the register indicated by the instruction to the location in memory
indicated by the instruction, then returns the error code value. 
The instruction is in the IR of the given CPU. This store uses a register addressing mode.

parameter (the_cpu): Pointer to the CPU to be used.

return value: The int value of the error code.
*/
int cpu_STBRegister(CPUPtr the_cpu);
/*
Stores the word in the register indicated by the instruction to the location in memory
indicated by the instruction, then returns the error code value. 
The instruction is in the IR of the given CPU. This store uses a base pointer addressing mode.

parameter (the_cpu): Pointer to the CPU to be used.

return value: The int value of the error code.
*/
int cpu_STWBase(CPUPtr the_cpu);

/*
Stores the low-order byte in the register indicated by the instruction to the location in memory
indicated by the instruction, then returns the error code value. 
The instruction is in the IR of the given CPU. This store uses a base pointer addressing mode.

parameter (the_cpu): Pointer to the CPU to be used.

return value: The int value of the error code.
*/
int cpu_STBBase(CPUPtr the_cpu);

/*
Stores the word in the register indicated by the instruction to the location in memory
indicated by the instruction, then returns the error code value. 
The instruction is in the IR of the given CPU. This store uses an index register addressing mode.

parameter (the_cpu): Pointer to the CPU to be used.

return value: The int value of the error code.
*/
int cpu_STWIndexReg(CPUPtr the_cpu);

/*
Stores the low-order byte in the register indicated by the instruction to the location in memory
indicated by the instruction, then returns the error code value. 
The instruction is in the IR of the given CPU. This store uses an index register addressing mode.

parameter (the_cpu): Pointer to the CPU to be used.

return value: The int value of the error code.
*/
int cpu_STBIndexReg(CPUPtr the_cpu);

/*
Stores the word in the register indicated by the instruction to the location in memory
indicated by the instruction, then returns the error code value. 
The instruction is in the IR of the given CPU. This store uses an indirect addressing mode.

parameter (the_cpu): Pointer to the CPU to be used.

return value: The int value of the error code.
*/
int cpu_STWIndirect(CPUPtr the_cpu);

/*
Stores the low-order byte in the register indicated by the instruction to the location in memory
indicated by the instruction, then returns the error code value. 
The instruction is in the IR of the given CPU. This store uses an indirect addressing mode.

parameter (the_cpu): Pointer to the CPU to be used.

return value: The int value of the error code.
*/
int cpu_STBIndirect(CPUPtr the_cpu);

/*
Sets the contents of the given int pointers to the register numbers extracted from the
instruction in the given CPU. Returns the value of the error code.

parameter (the_cpu): Pointer to the CPU used.
parameter (the_reg_num_dest_ptr): Pointer to the int value of the source register number
indicated by the instruction.
parameter (the_reg_num_address_ptr); Pointer to the int value of the address register number
indicated by the instruction.

return value: The int value of the error code. 
*/
int cpu_getRegNumbersForStore(CPUPtr the_cpu, int* the_reg_num_src_ptr, int* the_reg_num_address_ptr);








// Load Operations

int cpu_LDA(CPUPtr the_cpu);

/*
Calls the appropriate LDW function based on the given mod value and returns
the value of the error code.

parameter (the_cpu): Pointer to the CPU used.

return value: The int value of the error code.
*/
int cpu_LDW(CPUPtr the_cpu, int the_mod);

/*
Calls the appropriate LDB function based on the given mod value and returns
the value of the error code.

parameter (the_cpu): Pointer to the CPU used.

return value: The int value of the error code.
*/
int cpu_LDB(CPUPtr the_cpu, int the_mod);

/*
Loads a word from memory into the register indicated by the instruction. The instruction
comes from the given CPU's IR. This load uses base pointer addressing mode.

parameter (the_cpu): Pointer to the CPU to use.

return value: The int value of the error code.
*/
int cpu_LDWBase(CPUPtr the_cpu);

/*
Loads a byte from memory into the low-order byte of the register indicated by the instruction. The instruction
comes from the given CPU's IR. This load uses a base pointer addressing mode.

parameter (the_cpu): Pointer to the CPU to use.

return value: The int value of the error code. 
*/
int cpu_LDBBase(CPUPtr the_cpu);

/*
Loads a word from memory into the register indicated by the instruction and returns the
value of the error code. The instruction comes from the given CPU's IR.
This load uses an index register addressing mode.

parameter (the_cpu): Pointer to the CPU to use.

return value: The int value of the error code. 
*/
int cpu_LDWIndexReg(CPUPtr the_cpu);

/*
Loads a byte from memory into the low-order byte of the register indicated by the instruction and returns the
value of the error code. The instruction comes from the given CPU's IR.
This load uses an index register addressing mode.

parameter (the_cpu): Pointer to the CPU to use.

return value: The int value of the error code. 
*/
int cpu_LDBIndexReg(CPUPtr the_cpu);




/*
Loads a word from memory into the register indicated by the instruction. The instruction
comes from the given CPU's IR. This load uses register addressing mode.

parameter (the_cpu): Pointer to the CPU to use.

return value: The int value of the error code.
*/
int cpu_LDWRegister(CPUPtr the_cpu);

/*
Loads a byte from memory into the low-order byte of the register indicated by the instruction. The instruction
comes from the given CPU's IR. This load uses register addressing mode.

parameter (the_cpu): Pointer to the CPU to use.

return value: The int value of the error code.
*/
int cpu_LDBRegister(CPUPtr the_cpu);

/*
Loads a word from memory into the register indicated by the instruction. The instruction
comes from the given CPU's IR. This load uses indirect addressing mode.

parameter (the_cpu): Pointer to the CPU to use.

return value: The int value of the error code.
*/
int cpu_LDWIndirect(CPUPtr the_cpu);

/*
Loads a byte from memory into the low-order byte of the register indicated by the instruction. The instruction
comes from the given CPU's IR. This load uses indirect addressing mode.

parameter (the_cpu): Pointer to the CPU to use.

return value: The int value of the error code.
*/
int cpu_LDBIndirect(CPUPtr the_cpu);

/*
Loads the sign extended immediate value into the register indicated by the instruction, and
returns the value of the error code. The instruction is contained in the given CPU's IR.

parameter (the_cpu): Pointer to the CPU to use.

return value: The int value of the error code.
*/
int cpu_LDI(CPUPtr the_cpu);

/*
Moves the contents of a register to another register specified in the instruction.

parameter (the_cpu): Pointer to the CPU to use.

return value: The int value of the error code.
*/
int cpu_MOV(CPUPtr the_cpu);

/*
Increments the value in the given register of the given CPU.

parameter (the_cpu): Pointer to the CPU whose register is incremented.
parameter (the_register_number): The number of the register to increment.

return value: The int value of the error code. 
*/
int cpu_incrementRegister(CPUPtr the_cpu, int the_register_number);

/*
Sets the contents of the given int pointers to the register numbers extracted from the
instruction in the given CPU. Returns the value of the error code.

parameter (the_cpu): Pointer to the CPU used.
parameter (the_reg_num_dest_ptr): Pointer to the int value of the destination register number
indicated by the instruction.
parameter (the_reg_num_address_ptr); Pointer to the int value of the address register number
indicated by the instruction.

return value: The int value of the error code. 
*/
int cpu_getRegNumbersForLoad(CPUPtr the_cpu, int* the_reg_num_dest_ptr, int* the_reg_num_address_ptr);







// Branch Operations

/*
Branches to the address at PC + 1 + offset as indicated by
the instruction, then returns the value of the erorr code. 
The PC used is in the given CPU.

parameter (the_cpu): Pointer to the CPU to be used.

return value: The int value of the error code.
*/
int cpu_BRI(CPUPtr the_cpu);





// JSR and RET Operations

/*
Executes a JSR with the given CPU and returns the error code.

parameter (the_cpu): Pointer to the CPU to be used.

return value: The int value of the error code.
*/
int cpu_JSR(CPUPtr the_cpu);

/*
Executes a RET with the given CPU and returns the error code.

parameter (the_cpu): Pointer to the CPU to be used.

return value: The int value of the error code.
*/
int cpu_RET(CPUPtr the_cpu);






// Stack Operations

/*
Selects the appropriate stack operation with the given mod.

parameter (the_cpu): Pointer to the CPU to be used.
parameter (the_mod): The mod value to be used.

return value: The int value of the error code.
*/
int cpu_StackOps(CPUPtr the_cpu, int the_mod);


/*
Pushes the word indicated by the instruction onto the stack, preserving
big endian order.

parameter (the_cpu): Pointer to the CPU to be used.

return value: The int value of the error code.
*/
int cpu_PUSHW(CPUPtr the_cpu);

/*
Pushes the byte indicated by the instruction onto the stack.

parameter (the_cpu): Pointer to the CPU to be used.

return value: The int value of the error code.
*/
int cpu_PUSHB(CPUPtr the_cpu);

/*
Pops a word off the stack to the register indicated by the instruction.

parameter (the_cpu): Pointer to the CPU to be used.

return value: The int value of the error code.
*/
int cpu_POPW(CPUPtr the_cpu);

/*
Pops a byte off the stack into the low order byte of the register indicated by the instruction.

parameter (the_cpu): Pointer to the CPU to be used.

return value: The int value of the error code.
*/
int cpu_POPB(CPUPtr the_cpu);

/*
Adds the given value to the stack pointer and returns the error code value.
If a negative value is given, the stack pointer is decremented, moving it towards
memory[0]. If a positive value is given, the stack pointer is incremented, moving
it away from memory[0].

parameter (the_cpu): Pointer to the CPU used.
parameter (the_value): The value added to the stack pointer.

return value: The int value of the error code.
*/
int cpu_AddValToStackPointer(CPUPtr the_cpu, int the_value);




// IN and OUT

int cpu_IN(CPUPtr the_cpu, ushort port_number);

int cpu_OUT(CPUPtr the_cpu, ushort port_number);




// Setters and Getters


/*
Checks the condition codes of the SW against the input condition codes.

return value : Nonzero integer if condition codes match; zero for false.
*/
int cpu_checkFlags(CPUPtr the_cpu,int the_cc);

/*
Returns the value in the status word of the CPU.

parameter (the_cpu_ptr): Pointer to the CPU whose status word is returned.
parameter (the_error): Pointer to the error code value of this function.

return value: The value of the status word register.
*/
Register cpu_getSW(CPUPtr the_cpu_ptr, int* the_error);

/*
Sets the given CPU's status word to the given value and returns the error code value.

parameter (the_cpu_ptr): Pointer to the CPU whose status word is changed.
parameter (the_status_word): Register value to be placed in the given CPU's status word.

return value: The value of the error code for this function.
*/
int cpu_setSW(CPUPtr the_cpu_ptr, Register the_status_word);

/*
Returns the value in the IR of the CPU.

parameter (the_cpu_ptr): Pointer to the CPU whose IR is returned.
parameter (the_error): Pointer to the error code value of this function.

return value: The value of the IR register.
*/
Register cpu_getIR(CPUPtr the_cpu_ptr, int* the_error);

/*
Sets the given CPU's IR to the given value and returns the error code value.

parameter (the_cpu_ptr): Pointer to the CPU whose IR is changed.
parameter (the_status_word): Register value to be placed in the given CPU's IR.

return value: The value of the error code for this function.
*/
int cpu_setIR(CPUPtr the_cpu_ptr, Register the_ir);

/*
Returns the value in the PC of the CPU.

parameter (the_cpu_ptr): Pointer to the CPU whose PC is returned.
parameter (the_error): Pointer to the error code value of this function.

return value: The value of the PC register.
*/
Register cpu_getPC(CPUPtr the_cpu_ptr, int* the_error);

/*
Sets the given CPU's PC to the given value and returns the error code value.

parameter (the_cpu_ptr): Pointer to the CPU whose PC is changed.
parameter (the_status_word): Register value to be placed in the given CPU's PC.

return value: The value of the error code for this function.
*/
int cpu_setPC(CPUPtr the_cpu_ptr, Register the_pc);

/*
Returns the value in the MAR of the CPU.

parameter (the_cpu_ptr): Pointer to the CPU whose MAR is returned.
parameter (the_error): Pointer to the error code value of this function.

return value: The value of the MAR register.
*/
Register cpu_getMAR(CPUPtr the_cpu_ptr, int* the_error);

/*
Sets the given CPU's MAR to the given value and returns the error code value.

parameter (the_cpu_ptr): Pointer to the CPU whose MAR is changed.
parameter (the_status_word): Register value to be placed in the given CPU's MAR.

return value: The value of the error code for this function.
*/
int cpu_setMAR(CPUPtr the_cpu_ptr, Register the_mar);

/*
Returns the value in the MDR of the CPU.

parameter (the_cpu_ptr): Pointer to the CPU whose MDR is returned.
parameter (the_error): Pointer to the error code value of this function.

return value: The value of the MDR register.
*/
Register cpu_getMDR(CPUPtr the_cpu_ptr, int* the_error);

/*
Sets the given CPU's MDR to the given value and returns the error code value.

parameter (the_cpu_ptr): Pointer to the CPU whose MDR is changed.
parameter (the_status_word): Register value to be placed in the given CPU's MDR.

return value: The value of the error code for this function.
*/
int cpu_setMDR(CPUPtr the_cpu_ptr, Register the_mdr);

/*
Returns the macrostate of the CPU.

parameter (the_cpu_ptr): Pointer to the CPU whose macrostate is returned.
parameter (the_error): Pointer to the error code value of this function.

return value: The value of the macrostate.
*/
int cpu_getMacroState(CPUPtr the_cpu_ptr, int* the_error);

/*
Sets the given CPU's macrostate to the given value and returns the error code value.

parameter (the_cpu_ptr): Pointer to the CPU whose macrostate is changed.
parameter (the_status_word): int value to be placed in the given CPU's macrostate.

return value: The value of the error code for this function.
*/
int cpu_setMacroState(CPUPtr the_cpu_ptr, int the_macroState);

/*
Returns the microstate of the CPU.

parameter (the_cpu_ptr): Pointer to the CPU whose microstate is returned.
parameter (the_error): Pointer to the error code value of this function.

return value: The value of the microstate.
*/
int cpu_getMicroState(CPUPtr the_cpu_ptr, int* the_error);

/*
Sets the given CPU's microstate to the given value and returns the error code value.

parameter (the_cpu_ptr): Pointer to the CPU whose microstate is changed.
parameter (the_status_word): int value to be placed in the given CPU's microstate.

return value: The value of the error code for this function.
*/
int cpu_setMicroState(CPUPtr the_cpu_ptr, int the_microState);
#endif

/* End Program */
